//
//  ModuleManager.swift
//  
//
//  Created by tank on 2021/9/29.
//

import Foundation
import Logging
import UIKit
import LibBase
import LibService

public protocol ModuleManagerDataSource: AnyObject {
    var jsonPath: String { get }
    
    func lookupKey(forAsset: String, fromPackage: String) -> String
}

/// Module manager
public class ModuleManager {
    static public let shared = ModuleManager()
    
    var logger = Logger(label: "LibModuleManager.ModuleManager")
    
    public weak var dataSource: ModuleManagerDataSource?
    
    /// module classed
    public private(set) var moduleClasses: [String: ModuleProtocol.Type] = [:]
    
    private var modules = [ModuleProtocol]()
    
    private init() {
        logger.logLevel = .debug
    }
    
    /// 注册模块
    /// - Parameter module: 模块类
    public func register(module: ModuleProtocol.Type) {
        moduleClasses[module.type] = module
    }
    
    public func module(type: String, id: String?) -> ModuleProtocol? {
        if let module = modules.first(where: { element in
            return element.type == type && element.id == id
        }) {
            return module
        }
        
        guard let moduleClass = moduleClasses[type] else {
            return nil
        }
        
        let module = moduleClass.init(id: id)
        modules.append(module)
        
        return module
    }
    
    /// Get view controller
    /// - Parameter url: url
    /// - Returns: UIViewController
    public func viewController(url: String,
                               config: PageConfig? = nil,
                               params: [String: Any]? = nil) -> PageController? {
        guard let urlComponents = URLComponents.ex.create(string: url) else {
            return nil
        }
        
        return viewController(urlComponents: urlComponents, config: config, params: params)
    }
    
    public func viewController(urlComponents: URLComponents,
                               config: PageConfig? = nil,
                               params: [String: Any]? = nil) -> PageController? {
        guard let pageBuildModel = BuildModel(urlComponents: urlComponents,
                                              params: params),
              pageBuildModel.host == "page" else {
            return nil
        }
        
        return viewController(moduleType: pageBuildModel.moduleType,
                              moduleId: pageBuildModel.moduleId,
                              pageType: pageBuildModel.type,
                              pageId: pageBuildModel.id,
                              config: config,
                              params: pageBuildModel.params,
                              hash: pageBuildModel.hash)
    }
    
    public func viewController(moduleType: String, moduleId: String?,
                               pageType: String?, pageId: String?,
                               config: PageConfig?,
                               params: [String: Any]? = nil,
                               hash: String? = nil) -> PageController? {
        return module(type: moduleType, id: moduleId)?
            .page(type: pageType,
                  id: pageId,
                  config: config,
                  params: params,
                  hash: hash)?
            .viewController
    }
    
    public func handle(url: String, params: [String: Any]?,
                       completion: RouterServiceProtocol.RouteCompletion?) {
        guard let urlComponents = URLComponents.ex.create(string: url) else {
            completion?(.error, nil)
            return
        }
        
        handle(urlComponents: urlComponents, params: params, completion: completion)
    }
    
    public func handle(urlComponents: URLComponents, params: [String: Any]?,
                       completion: RouterServiceProtocol.RouteCompletion?) {
        guard let handlerBuildModel = BuildModel(urlComponents: urlComponents, params: params),
              handlerBuildModel.host == "handler" else {
            completion?(.error, nil)
            return
        }
        
        guard let module = module(type: handlerBuildModel.moduleType,
                                  id: handlerBuildModel.moduleId) else {
            completion?(.error, nil)
            return
        }
        
        module.handle(type: handlerBuildModel.type,
                      params: handlerBuildModel.params,
                      completion: completion)
    }
    
    func removeModule(type: String, id: String?) {
        modules.removeAll { $0.type == type && $0.id == id }
        
        logger.debug("Remove module type = \(type), id = \(id ?? "null")")
        logger.debug("Module count: \(modules.count)")
    }
}
